﻿#pragma once

#include <iostream>
#include <string>

#include <glad/glad.h>
//
#include <GLFW/glfw3.h>
#include <xy/geom/vec.h>

using namespace xy::geom;

class Shader
{
  public:
    /**
     * @brief 初始化着色器
     *
     * @param[in] vertexPath
     * @param[in] fragmentPath
     * @param[in] geometryPath
     */
    Shader(const char *vertexPath, const char *fragmentPath, const char *geometryPath);

    /**
     * @brief 设置 uniform 变量的值
     *
     * @tparam T
     * @param[in] var
     * @param[in] val
     */
    template <typename T> void set_value(const char *var, const T &val)
    {
        if constexpr (std::is_same_v<T, int>)
            glUniform1i(glGetUniformLocation(m_ID, var), val);
        else if constexpr (std::is_same_v<T, float>)
            glUniform1f(glGetUniformLocation(m_ID, var), val);
        else if constexpr (std::is_same_v<T, vec2f>)
            glUniform2f(glGetUniformLocation(m_ID, var), val.x(), val.y());
        else if constexpr (std::is_same_v<T, vec3f>)
            glUniform3f(glGetUniformLocation(m_ID, var), val.x(), val.y(), val.z());
        else if constexpr (std::is_same_v<T, vec4f>)
            glUniform4f(glGetUniformLocation(m_ID, var), val.x(), val.y(), val.z(), val.w());
        else if constexpr (std::is_same_v<T, mat4x4f>)
        {
            unsigned int loc = glGetUniformLocation(m_ID, var);

            // GL_TRUE 表示矩阵转置以后传入
            glUniformMatrix4fv(loc, 1, GL_TRUE, val.data());
        }
        else
            throw std::runtime_error("Unsupported type!");
    }

    /**
     * @brief 启用着色器
     *
     */
    void enable();

    /**
     * @brief 析构函数
     *
     */
    ~Shader();

  private:
    /**
     * @brief 加载着色器
     *
     * @param[in] path
     * @param[in] type
     * @return unsigned
     */
    unsigned int _load(const char *path, int type);

    /**
     * @brief 检查编译错误
     *
     * @param[in] shader
     * @param[in] type
     */
    void _check_compile_errors(unsigned int shader, std::string type);

  protected:
    unsigned int m_ID;
};
